package com.zhxin.threadLab.summary.chapter2;



import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @ClassName DefaultThreadPool
 * @Description //简单线程池实现 示例
 * @Author singleZhang
 * @Email 405780096@qq.com
 * @Date 2020/12/1 0001 下午 2:49
 **/
public class DefaultThreadPool<Job extends Runnable> implements ThreadPool<Job> {

    private static final int MAX_WORKER_NUM = 10;  //线程池最大容量
    private static final int NORMAL_WORKER_NUM = 5;//线程池默认容量
    private static final int MIN_WORKER_NUM = 1;//线程池最小容量

    //工作列表
    private final LinkedList<Job> jobs = new LinkedList<Job>();

    //工作者列表
    private final List<Worker> workers = Collections.synchronizedList(new ArrayList<Worker>());

    //工作者数量
    private int workerNum = NORMAL_WORKER_NUM;

    //线程编号生成
    private AtomicInteger threadId = new AtomicInteger();

    public DefaultThreadPool(int num){
        workerNum  = num > MAX_WORKER_NUM ? MAX_WORKER_NUM: (Math.max(num, MIN_WORKER_NUM));
        initializeWorker(NORMAL_WORKER_NUM);

    }

    /**
     * 执行工作
     *
     * @param job*/
    public void execute(Job job){
        if(job != null){
            synchronized (jobs){
                jobs.add(job);
                jobs.notify();
            }
        }
    }

    /**
     * 关闭工作
     * */
    public void shutDown(){
        for(Worker worker:workers){
            worker.shutDown();
        }
    }

    /**
     * 增加工作者线程
     * */
    public void addWorker(int num){
        synchronized (jobs){

            //增加数超过容量限制,把总数限制在容量临界值
            if(num + this.workerNum > MAX_WORKER_NUM){
                num = MAX_WORKER_NUM - this.workerNum;
            }

            initializeWorker(num);
            this.workerNum += num;
        }
    }

    /**
     * 减少工作者线程
     * */
    public void removeWorker(int num){
        synchronized (jobs){
            if(num > this.workerNum){
                throw new IllegalArgumentException("beyond workerNum");
            }

            int count = 0;
            while(count < workerNum){
                Worker worker = workers.get(count);
                if(workers.remove(worker)){
                    worker.shutDown();
                    count ++;
                }
            }
            this.workerNum -= count;
        }
    }

    /**
     * 获取工作量
     * */
    public int getJobSize(){
        return jobs.size();
    }

    /**
     * 线程初始化
     * */
    private void initializeWorker(int num){
        for(int i=0;i<num;i++){
            Worker worker = new Worker();
            workers.add(worker);
            Thread thread = new Thread(worker,"Thread-Pool-ThreadId:"+threadId);
            threadId.incrementAndGet();
            thread.start();
        }
    }

    class Worker implements Runnable {

        // 工作状态
        private volatile boolean running = true;

        public void run(){
            while (running){
                Job job = null;
                synchronized (jobs){
                    //如果工作列表是空的,等待
                    while(jobs.isEmpty()){
                       try{
                           jobs.wait();
                       }catch (InterruptedException e){
                           //中断返回
                           System.out.println(e.getMessage());
                           Thread.currentThread().interrupt();
                           return;
                       }
                    }

                    job = jobs.removeFirst(); //获取第一个任务
                }

                if(job != null){
                    job.run();
                }
            }
        }

        public void shutDown(){
            running = false;
        }

    }

    /*
    * 说明
    * 从线程池的实现可以看到， 当客户端调用execute(Job) 方法时， 会不断地向任务列
    * 表jobs中添加Job， 而每个工作者线程会不断地从jobs上取出一个Job进行执行， 当
    * jobs为空时， 工作者线程进入等待状态。
    * 添加一个Job后， 对工作队列jobs调用了其notify(方法， 而不是notifyAll方法，
    * 因为能够确定有工作者线程被唤醒， 这时使用notify() 方法将会比notifyAll() 方法获
    * 得更小的开销(避免将等待队列中的线程全部移动到阻塞队列中)。
    * 可以看到，线程池的本质就是使用了一个线程安全的工作队列连接工作者线程和客
    * 户端线程，客户端线程将任务放入工作队列后便返回，而工作者线程则不断地从工
    * 作队列上取出工作并执行。当工作队列为空时，所有的工作者线程均等待在工作队
    * 列上，当有客户端提交了一个任务之后会通知任意一个工作者线程，随着大量的任
    * 务被提交，更多的工作者线程会被唤醒。
    *
    *
    * */
}


